home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
OS
/
ZHandle.cpp
< prev
next >
Wrap
Text File
|
1997-06-20
|
16KB
|
769 lines
/*
* File: ZHandle.h
* Summary: A class to encapsulate relocatable memory.
* Written by: Jesse Jones
*
* Copyright ゥ 1996-1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <3> 6/20/97 JDJ Ctors use new SHandleOptions to work around ambiguity problems.
* <2> 5/17/97 JDJ Added an Invariant to ZHandleRef. OnLock now adds a
* tail to the handle.
* <1> 1/14/96 JDJ Created
*/
#include <ZHandle.h>
#include <Errors.h>
#include <Resources.h>
#include <ZConstants.h>
#include <ZDebug.h>
#include <ZExceptions.h>
#include <ZMemUtils.h>
#include <ZMiscUtils.h>
#include <ZReferenceCounted.h>
#include <ZResUtils.h>
#include <ZStringUtils.h>
//-----------------------------------
// Constants
//
const long kTail = 0x26374859L;
// ===================================================================================
// class ZHandleRef
// ===================================================================================
class ZHandleRef : public MInvariant, public MReferenceCounted, public MLockable {
typedef MInvariant Inherited;
friend THandle;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~ZHandleRef();
ZHandleRef(ulong bytes, const SHandleOptions& options);
ZHandleRef(Handle macHandle);
//-----------------------------------
// New API
//
public:
// ----- Access -----
const Byte* GetPtr() const;
Byte* GetPtr();
Handle GetHandle() const;
// ----- Sizing -----
ulong GetSize() const;
OSErr SetSize(ulong bytes, bool zeroBytes);
// ----- Debugging -----
void AddTail();
void CheckTail() const;
void RemoveTail();
//-----------------------------------
// Inherited API
//
protected:
virtual void Invariant() const;
virtual void OnLock(bool moveHigh);
virtual void OnUnlock();
//-----------------------------------
// Member data
//
private:
Handle mHandle;
bool mHasTail;
};
//---------------------------------------------------------------
//
// ZHandleRef::~ZHandleRef
//
//---------------------------------------------------------------
ZHandleRef::~ZHandleRef()
{
ASSERT(!mHasTail);
DisposeIfHandle(mHandle);
}
//---------------------------------------------------------------
//
// ZHandleRef::ZHandleRef (ulong, SHandleOptions)
//
//---------------------------------------------------------------
ZHandleRef::ZHandleRef(ulong bytes, const SHandleOptions& options)
{
ASSERT(bytes < 16*1024L*1024L);
mHasTail = false;
mHandle = CreateHandle(bytes, options.options);
ThrowIfMemFail(mHandle);
}
//---------------------------------------------------------------
//
// ZHandleRef::ZHandleRef (Handle)
//
//---------------------------------------------------------------
ZHandleRef::ZHandleRef(Handle takeHandle)
{
ValidateHandle(takeHandle);
mHasTail = false;
mHandle = takeHandle;
if (IsResource(mHandle)) {
if (*mHandle == nil) {
LoadResource(mHandle);
ThrowIfResError();
}
HNoPurge(mHandle);
DetachResource(mHandle);
ThrowIfResError();
}
if (::IsLocked(mHandle))
mLockCount = 1;
}
//---------------------------------------------------------------
//
// ZHandleRef::OnLock
//
//---------------------------------------------------------------
void ZHandleRef::OnLock(bool moveHigh)
{
#if DEBUG
this->AddTail();
#endif
if (moveHigh)
MoveHHi(mHandle);
HLock(mHandle);
}
//---------------------------------------------------------------
//
// ZHandleRef::OnUnlock
//
//---------------------------------------------------------------
void ZHandleRef::OnUnlock()
{
HUnlock(mHandle);
#if DEBUG
this->RemoveTail();
#endif
}
//---------------------------------------------------------------
//
// ZHandleRef::GetPtr
//
//---------------------------------------------------------------
inline const Byte* ZHandleRef::GetPtr() const
{
return (Byte *) StripAddress(*mHandle);
}
//---------------------------------------------------------------
//
// ZHandleRef::GetPtr
//
//---------------------------------------------------------------
inline Byte* ZHandleRef::GetPtr()
{
return (Byte *) StripAddress(*mHandle);
}
//---------------------------------------------------------------
//
// ZHandleRef::GetHandle
//
//---------------------------------------------------------------
inline Handle ZHandleRef::GetHandle() const
{
ValidateHandle(mHandle);
return mHandle;
}
//---------------------------------------------------------------
//
// ZHandleRef::GetSize
//
//---------------------------------------------------------------
inline ulong ZHandleRef::GetSize() const
{
long size = ::GetHandleSize(mHandle);
if (mHasTail)
size -= 4;
return (ulong) size;
}
//---------------------------------------------------------------
//
// ZHandleRef::SetSize
//
//---------------------------------------------------------------
OSErr ZHandleRef::SetSize(ulong bytes, bool zeroBytes)
{
PRECONDITION(!mHasTail);
ASSERT(bytes < 16*1024L*1024L);
OSErr err = noErr;
long oldSize = ::GetHandleSize(mHandle);
if (bytes != oldSize) {
::SetHandleSize(mHandle, bytes);
err = MemError();
if (err == noErr && zeroBytes && bytes > oldSize)
ClearMemory(*mHandle + oldSize, bytes - oldSize);
}
POSTCONDITION(!mHasTail);
return err;
}
//---------------------------------------------------------------
//
// ZHandleRef::AddTail
//
//---------------------------------------------------------------
void ZHandleRef::AddTail()
{
#if DEBUG
ASSERT(!mHasTail);
ulong len = this->GetSize();
long* p = nil; // to insert another breakpoint
ThrowIfOSErr(this->SetSize(len+sizeof(long), kDontZeroBytes));
p = (long *) (this->GetPtr() + len);
*p = kTail;
mHasTail = true;
#endif
}
//---------------------------------------------------------------
//
// ZHandleRef::CheckTail
//
//---------------------------------------------------------------
void ZHandleRef::CheckTail() const
{
#if DEBUG
ASSERT(mHasTail);
ulong len = this->GetSize(); // Note that GetSize adjusts for the tail!
long* p = (long *) (this->GetPtr() + len);
if (*p != kTail)
DEBUGSTR("The handle's tail has been changed to %lX.¥n", *p);
#endif
}
//---------------------------------------------------------------
//
// ZHandleRef::RemoveTail
//
//---------------------------------------------------------------
void ZHandleRef::RemoveTail()
{
#if DEBUG
this->CheckTail();
mHasTail = false;
ulong len = this->GetSize(); // Note that GetSize adjusts for the tail!
ThrowIfOSErr(this->SetSize(len, kDontZeroBytes));
#endif
}
//---------------------------------------------------------------
//
// ZHandleRef::Invariant
//
//---------------------------------------------------------------
void ZHandleRef::Invariant() const
{
Inherited::Invariant();
ASSERT(mHandle != nil);
ASSERT(*mHandle != nil);
if (::IsLocked(mHandle))
ASSERT(this->IsLocked());
if (this->IsLocked())
ASSERT(::IsLocked(mHandle));
if (mHasTail)
this->CheckTail();
}
#pragma mark -
// ===================================================================================
// class THandle
// ===================================================================================
//---------------------------------------------------------------
//
// THandle::~THandle
//
//---------------------------------------------------------------
THandle::~THandle()
{
mHandleRef->RemoveReference();
}
//---------------------------------------------------------------
//
// THandle::THandle (ulong, SHandleOptions)
//
//---------------------------------------------------------------
THandle::THandle(ulong bytes, const SHandleOptions& options)
{
mHandleRef = new ZHandleRef(bytes, options);
}
//---------------------------------------------------------------
//
// THandle::THandle (Handle)
//
//---------------------------------------------------------------
THandle::THandle(Handle takeHandle)
{
ASSERT(takeHandle != nil);
try {
mHandleRef = new ZHandleRef(takeHandle);
} catch (...) {
if (IsResource(takeHandle))
ReleaseResource(takeHandle);
else
DisposeHandle(takeHandle);
throw;
}
}
//---------------------------------------------------------------
//
// THandle::THandle (THandle)
//
//---------------------------------------------------------------
THandle::THandle(const THandle& hand)
{
mHandleRef = hand.mHandleRef;
mHandleRef->AddReference();
}
//---------------------------------------------------------------
//
// THandle::THandle (ResType, ResID, SHandleOptions, short)
//
//---------------------------------------------------------------
THandle::THandle(ResType type, ResID id, const SHandleOptions& options, short fileRef)
{
Handle rsrc = nil;
try {
TSaveResFile setFile(fileRef);
// Read the resource into the app's heap, but don't read the resource's data.
SetResLoad(false);
if (fileRef == kNoFileRefNum)
rsrc = GetResource(type, id);
else
rsrc = Get1Resource(type, id);
OSErr err = ResError();
SetResLoad(true);
if (rsrc == nil && err == noErr)
err = resNotFound;
ThrowIfOSErr(err);
// Find the size of the resource's data.
ulong bytes = (ulong) GetResourceSizeOnDisk(rsrc);
ThrowIfResError();
// Allocate a handle of the right size in the correct location.
mHandleRef = new ZHandleRef(bytes, options);
// Read in the resource's data.
this->Lock();
ReadPartialResource(rsrc, 0, this->GetPtr(), (long) bytes);
err = ResError();
this->Unlock();
ThrowIfOSErr(err);
// Release our resource handle.
ReleaseResource(rsrc);
rsrc = nil;
} catch (...) {
ReleaseIfResource(rsrc);
throw;
}
}
//---------------------------------------------------------------
//
// THandle::THandle (ResType, string, SHandleOptions, short)
//
//---------------------------------------------------------------
THandle::THandle(ResType type, const string& name, const SHandleOptions& options, short fileRef)
{
Handle rsrc = nil;
try {
TSaveResFile setFile(fileRef);
// Read the resource into the app's heap, but don't read the resource's data.
SetResLoad(false);
if (fileRef == kNoFileRefNum)
rsrc = GetNamedResource(type, StrToPStr(name));
else
rsrc = Get1NamedResource(type, StrToPStr(name));
OSErr err = ResError();
SetResLoad(true);
if (rsrc == nil && err == noErr)
err = resNotFound;
ThrowIfOSErr(err);
// Find the size of the resource's data.
ulong bytes = (ulong) GetResourceSizeOnDisk(rsrc);
ThrowIfResError();
// Allocate a handle of the right size in the correct location.
mHandleRef = new ZHandleRef(bytes, options);
// Read in the resource's data.
this->Lock();
ReadPartialResource(rsrc, 0, this->GetPtr(), (long) (bytes));
err = ResError();
this->Unlock();
ThrowIfOSErr(err);
// Release our resource handle.
ReleaseResource(rsrc);
rsrc = nil;
} catch (...) {
ReleaseIfResource(rsrc);
throw;
}
}
//---------------------------------------------------------------
//
// THandle::operator=
//
//---------------------------------------------------------------
THandle& THandle::operator=(const THandle& hand)
{
ASSERT(!this->IsLocked());
if (mHandleRef != hand.mHandleRef) {
mHandleRef->RemoveReference();
hand.mHandleRef->AddReference();
mHandleRef = hand.mHandleRef;
}
return *this;
}
//---------------------------------------------------------------
//
// THandle::Detach
//
//---------------------------------------------------------------
void THandle::Detach()
{
ASSERT(!this->IsLocked());
if (mHandleRef->GetRefCount() > 1) {
Handle data = mHandleRef->GetHandle();
OSErr err = HandToHand(&data);
ThrowIfOSErr(err);
try {
ZHandleRef* newRef = new ZHandleRef(data);
mHandleRef->RemoveReference();
mHandleRef = newRef;
} catch(...) {
if (data != nil)
DisposeHandle(data);
throw;
}
}
}
//---------------------------------------------------------------
//
// THandle::Lock
//
//---------------------------------------------------------------
void THandle::Lock(bool moveHigh)
{
mHandleRef->Lock(moveHigh);
}
//---------------------------------------------------------------
//
// THandle::Unlock
//
//---------------------------------------------------------------
void THandle::Unlock()
{
mHandleRef->Unlock();
}
//---------------------------------------------------------------
//
// THandle::IsLocked
//
//---------------------------------------------------------------
bool THandle::IsLocked() const
{
return mHandleRef->IsLocked();
}
//---------------------------------------------------------------
//
// THandle::GetPtr
//
//---------------------------------------------------------------
const Byte* THandle::GetPtr() const
{
ASSERT(mHandleRef->IsLocked());
const Byte* ptr = mHandleRef->GetPtr();
return ptr;
}
//---------------------------------------------------------------
//
// THandle::GetPtr
//
//---------------------------------------------------------------
Byte* THandle::GetPtr()
{
ASSERT(mHandleRef->IsLocked());
Byte* ptr = mHandleRef->GetPtr();
return ptr;
}
//---------------------------------------------------------------
//
// THandle::GetUnsafePtr
//
//---------------------------------------------------------------
const Byte* THandle::GetUnsafePtr() const
{
const Byte* ptr = mHandleRef->GetPtr();
return ptr;
}
//---------------------------------------------------------------
//
// THandle::GetUnsafePtr
//
//---------------------------------------------------------------
Byte* THandle::GetUnsafePtr()
{
Byte* ptr = mHandleRef->GetPtr();
return ptr;
}
//---------------------------------------------------------------
//
// THandle::operator Handle
//
//---------------------------------------------------------------
THandle::operator Handle() const
{
Handle hand = mHandleRef->GetHandle();
return hand;
}
//---------------------------------------------------------------
//
// THandle::AddTail
//
//---------------------------------------------------------------
void THandle::AddTail()
{
#if DEBUG
mHandleRef->AddTail();
#endif
}
//---------------------------------------------------------------
//
// THandle::CheckTail
//
//---------------------------------------------------------------
void THandle::CheckTail() const
{
#if DEBUG
mHandleRef->CheckTail();
#endif
}
//---------------------------------------------------------------
//
// THandle::RemoveTail
//
//---------------------------------------------------------------
#pragma segment ZDebug
void THandle::RemoveTail()
{
#if DEBUG
mHandleRef->RemoveTail();
#endif
}
//---------------------------------------------------------------
//
// THandle::GetSize
//
//---------------------------------------------------------------
ulong THandle::GetSize() const
{
ulong size = mHandleRef->GetSize();
return size;
}
//---------------------------------------------------------------
//
// THandle::SetSize
//
//---------------------------------------------------------------
void THandle::SetSize(ulong bytes, bool zeroBytes)
{
ASSERT(!this->IsLocked() || bytes < this->GetSize()); // it's really bad practice to try and expand a locked handle.
ThrowIfOSErr(mHandleRef->SetSize(bytes, zeroBytes));
}
//---------------------------------------------------------------
//
// THandle::CanPurge
//
//---------------------------------------------------------------
bool THandle::CanPurge(Handle gzHandle) const
{
return mHandleRef->GetHandle() != gzHandle && !this->IsLocked();
}
//---------------------------------------------------------------
//
// THandle::CanPurge
//
// Outlined so we can be sure it's in a resident segment.
//
//---------------------------------------------------------------
ulong THandle::PurgeableBytes() const
{
return this->GetSize();
}
//---------------------------------------------------------------
//
// THandle::operator==
//
//---------------------------------------------------------------
bool THandle::operator==(const THandle& rhs) const
{
bool equal = mHandleRef == rhs.mHandleRef;
if (!equal) {
ulong crc1 = ComputeCRC(this->GetUnsafePtr(), this->GetSize());
ulong crc2 = ComputeCRC(rhs.GetUnsafePtr(), rhs.GetSize());
equal = crc1 == crc2;
}
return equal;
}